#include <REGX52.H>

//引脚定义
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
sbit DS1302_SCLK=P3^6;

//寄存器写入地址/指令定义
// DS1302的寄存器地址定义，最高位固定为1，最低位0表示写，1表示读
#define DS1302_SECOND		0x80
#define DS1302_MINUTE		0x82
#define DS1302_HOUR			0x84
#define DS1302_DATE			0x86
#define DS1302_MONTH		0x88
#define DS1302_DAY			0x8A
#define DS1302_YEAR			0x8C
#define DS1302_WP			0x8E	//写保护

//时间数组，索引0~6分别为年、月、日、时、分、秒、星期
// 初始时间设置为2025年8月26日12:59:55 星期二
unsigned char DS1302_Time[]={25,8,26,12,59,55,2};

/**
  * @brief  DS1302初始化函数
  * @param  无
  * @retval 无
  * @note   初始化DS1302的CE和SCLK引脚为低电平
  */
void DS1302_Init()
{
	DS1302_CE=0;
	DS1302_SCLK=0;
}

/**
  * @brief  DS1302写字节函数
  * @param  Command: 命令字，指定要写入的寄存器地址
  * @param  Data: 要写入的数据
  * @retval 无
  * @note   先发送命令字，再发送数据，采用串行通信方式
  */
void DS1302_WriteByte(unsigned char Command,unsigned char Data)
{
	unsigned char i;
	DS1302_CE=1;
	
	// 发送命令字（8位），从低位到高位依次发送
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		//相当于将 Command 的第 i 位的数据依次（从最低位到最高位）发送到了 DS1302 芯片的 IO 引脚上。这是一种串行通信，一次只发送一位。

		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	
	// 发送数据（8位），从低位到高位依次发送
	for(i=0;i<8;i++)
	{
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	DS1302_CE=0;
}

/**
  * @brief  DS1302读字节函数
  * @param  Command: 命令字，指定要读取的寄存器地址
  * @retval 读取到的数据
  * @note   先发送命令字，再读取数据，采用串行通信方式
  */
unsigned char DS1302_ReadByte(unsigned char Command)
{
	unsigned char i;
	unsigned char Data=0x00;
	Command|=0x01;//读的最低位一定是1,写的地址或上0x01就是读的地址
	DS1302_CE=1;
	
	//写入
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=0;
		DS1302_SCLK=1;//目的是减少一帧数据
	}
	
	//检测io口状态
	for(i=0;i<8;i++)
	{
		DS1302_SCLK=1;
		DS1302_SCLK=0;
		if(DS1302_IO){Data|=(0x01<<i);}
		//| 操作的作用是：将 Data 变量的第 i 位强制设置为 1，而 Data 的其他位保持不变。
	}
	DS1302_CE=0;
	DS1302_IO=0;	//读取后将IO设置为0，否则读出的数据会出错
	return Data;
}

/**
  * @brief  设置DS1302时间
  * @param  无
  * @retval 无
  * @note   先将十进制时间转换为BCD码，然后写入DS1302寄存器
  */
void DS1302_SetTime()
{
	DS1302_WriteByte(DS1302_WP,0x00);//关闭写保护，允许写入
	//0x8e为写保护寄存器，需先置0
	
	// 将十进制时间转换为BCD码并写入相应寄存器
	// BCD码：用4位二进制表示1位十进制数
	DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
	DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
	DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
	DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
	DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
	DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
	DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
	DS1302_WriteByte(DS1302_WP,0x80);//开启写保护，防止误写入
}

/**
  * @brief  读取DS1302时间
  * @param  无
  * @retval 无
  * @note   从DS1302读取BCD码时间数据，转换为十进制后存入时间数组
  */
void DS1302_ReadTime()
{
	unsigned char Temp=0x00;
	Temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制后读取
	Temp=DS1302_ReadByte(DS1302_MONTH);
	DS1302_Time[1]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DATE);
	DS1302_Time[2]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_Time[3]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_Time[4]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_Time[5]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_Time[6]=Temp/16*10+Temp%16;
	
}